package cn.yoshii.ad.adserver.util

import java.text.SimpleDateFormat
import java.util.*

/**
 * date : 2021-03-12 18:23
 * author : Xiang
 * description ： 日历转换
 */

inline val ONE_DAY_MILLISECONDS: Long
    get() = 86400000L

inline val ONE_HOUR_MILLISECONDS: Long
    get() = 3600000L

inline var Calendar.year: Int
    get() = this[Calendar.YEAR]
    set(value) {
        this[Calendar.YEAR] = value
    }

/**
 * 注意这里月份从1开始
 */
inline var Calendar.month: Int
    get() = this[Calendar.MONTH] + 1
    set(value) {
        this[Calendar.MONTH] = value - 1
    }

inline var Calendar.day: Int
    get() = this[Calendar.DAY_OF_MONTH]
    set(value) {
        this[Calendar.DAY_OF_MONTH] = value
    }

inline var Calendar.dayOfYear: Int
    get() = this[Calendar.DAY_OF_YEAR]
    set(value) {
        this[Calendar.DAY_OF_YEAR] = value
    }

inline val Calendar.week: Int
    get() = this[Calendar.DAY_OF_WEEK]

inline val Calendar.hourOfDay: Int
    get() = this[Calendar.HOUR_OF_DAY]

inline val Calendar.minuteOfHour: Int
    get() = this[Calendar.MINUTE]

inline val Calendar.minuteOfDay: Int
    get() = hourOfDay * 60 + minuteOfHour

/**
 * 当月多少天
 */
inline val Calendar.daysOfThisMonth: Int
    get() = getActualMaximum(Calendar.DAY_OF_MONTH)

/**
 * 当年有多少天
 */
inline val Calendar.daysOfThisYear: Int
    get() = getActualMaximum(Calendar.DAY_OF_YEAR)

/**
 * 清除非日期信息
 */
fun Calendar.clearTime() {
    this[Calendar.HOUR_OF_DAY] = 0
    this[Calendar.MINUTE] = 0
    this[Calendar.SECOND] = 0
    this[Calendar.MILLISECOND] = 0
}

fun Calendar.toInt(): Int {
    return year * 10000 + month * 100 + day
}

fun Int.toCalendar(): Calendar {
    val c = Calendar.getInstance()
    c.fromInt(this)
    return c
}

fun Long.toCalendar(): Calendar {
    val c = Calendar.getInstance()
    c.timeInMillis = this
    return c
}

/**
 * 现在
 */
fun now(): Calendar {
    return Calendar.getInstance()
}

/**
 * 今天，去掉时间
 */
fun today(): Calendar {
    val c = Calendar.getInstance()
    c.clearTime()
    return c
}

/**
 * 整形表示的今天
 */
fun todayInt(): Int {
    return today().toInt()
}

/**
 * 时间设置为今天最后一毫秒
 */
fun Calendar.timeToLastPoint() {
    this[Calendar.HOUR_OF_DAY] = 23
    this[Calendar.MINUTE] = 59
    this[Calendar.SECOND] = 59
    this[Calendar.MILLISECOND] = 999
}

fun Calendar.fromInt(value: Int) {
    clearTime()
    year = value / 10000
    month = value % 10000 / 100
    day = value % 100
}

fun Calendar.addMinutes(minutes: Int): Calendar {
    if (minutes == 0) return this
    add(Calendar.MINUTE, minutes)
    return this
}

fun Calendar.addDay(day: Int): Calendar {
    if (day == 0) return this
    add(Calendar.DAY_OF_YEAR, day)
    return this
}

/**
 * 只能保证月份正确，日期不一定正确
 * @param lastDay 是否指定为最后一天
 */
fun Calendar.addMonth(month: Int, lastDay: Boolean = false): Calendar {
    if (month == 0) return this
    add(Calendar.MONTH, month)
    if (lastDay) {
        this.day = daysOfThisMonth
    }
    return this
}

/**
 * 只能保证年份月份正确，日期不一定正确
 * @param lastDay 是否指定为最后一天
 */
fun Calendar.addYear(year: Int, lastDay: Boolean = false): Calendar {
    if (year == 0) return this
    add(Calendar.YEAR, year)
    if (lastDay) {
        set(Calendar.DAY_OF_YEAR, daysOfThisYear)
    }
    return this
}

fun Calendar.copy(): Calendar {
    return this.clone() as Calendar
}

fun Calendar.equal(c: Calendar): Boolean {
    return toInt() == c.toInt()
}

/**
 * 当月最后一天
 */
fun Calendar.thisMonthLastDay(): Calendar {
    val copy = copy()
    copy.day = daysOfThisMonth
    return copy
}

/**
 * 获取当前日期的映射周存储日期
 * 如果周一起点，存在这周一
 * 如果周日起点，1.日期是周日，存在明天，2.日期是非周日，存在这周一
 */
fun Calendar.mapWeekSaveDate(start: Int): Calendar {
    return if (start == Calendar.SUNDAY && week == Calendar.SUNDAY) {
        addDay(1)
    } else {
        thisWeekStart(Calendar.MONDAY)
    }
}

/**
 * 当前最近的星期week是什么日期
 */
fun Calendar.latestWeek(week: Int): Calendar {
    // 之前的week
    val pre = copy()
    var preCnt = 0
    while (true) {
        if (week == pre.week) {
            break
        }
        pre.addDay(-1)
        preCnt++
    }

    // 之后的week
    val post = copy()
    var postCnt = 0
    while (true) {
        if (week == post.week) {
            break
        }
        post.addDay(1)
        postCnt++
    }
    return if (preCnt < postCnt) pre else post
}

/**
 * 当月第num个week是几号
 */
fun Calendar.dayOfNumThWeek(num: Int, week: Int): Calendar {
    if (num <= 0) return Calendar.getInstance()
    val c = copy()
    c.day = 1
    // 找到第一个星期
    while (true) {
        if (week == c.week) {
            break
        }
        c.addDay(1)
    }
    c.day += (num - 1) * 7
    return c
}

/**
 * 这周的星期week 是几号
 * @param start 每周的起始星期，只有周一和周日两种情况
 */
fun Calendar.dayOfThisWeek(week: Int, start: Int): Calendar {
    val s = thisWeekStart(start)
    while (s.week != week) {
        s.addDay(1)
    }
    return s
}

/**
 * 本周的第一天
 * @param start 每周的起始星期，只有周一和周日两种情况
 */
fun Calendar.thisWeekStart(start: Int): Calendar {
    val c = this.copy()
    while (c.week != start) {
        c.addDay(-1)
    }
    return c
}

/**
 * 一周的起止日期
 */
fun Calendar.thisWeekRange(start: Int): Pair<Calendar, Calendar> {
    val s = thisWeekStart(start)
    val e = s.copy()
    e.addDay(6)
    return Pair(s, e)
}

/**
 * 日期是这周的第几天
 * @return 最小为0
 */
fun Calendar.weekIndex(start: Int): Int {
    // 如果今天是第一天，直接返回
    if (week == start) return 0
    // 找到下周第一天
    val c = this.copy()
    var n = 0
    while (c.week != start) {
        c.addDay(1)
        n++
    }
    return 7 - n
}

/**
 * 这个月每周的第一天
 */
fun Calendar.weekFirstDayOfTheMonth(start: Int): ArrayList<Calendar> {
    val list = ArrayList<Calendar>()
    val date = this.copy()
    date.day = 1
    // 找到第一个第一天
    while (date.week != start) {
        date.addDay(1)
    }
    list.add(date.copy())
    val last = date.thisMonthLastDay()
    date.addDay(7)
    while (date <= last) {
        list.add(date.copy())
        date.addDay(7)
    }
    return list
}

/**
 * 当年每月的第一天
 */
fun Calendar.monthFirstDayOfTheYear(): ArrayList<Calendar> {
    val list = ArrayList<Calendar>()
    (1..12).forEach {
        val c = this.copy()
        c.clearTime()
        c.month = it
        c.day = 1
        list.add(c)
    }
    return list
}

fun Calendar.toYMString(): String {
    val m = month
    val mStr = if (m >= 10) "$m" else "0$m"
    return "$year.$mStr"
}

fun Calendar.toMDString(): String {
    val m = month
    val mStr = if (m >= 10) "$m" else "0$m"
    val dStr = if (day >= 10) "$day" else "0$day"
    return "$mStr.$dStr"
}

fun Calendar.toShortMD(): String {
    return "$month.$day"
}

fun Calendar.toYMDString(): String {
    val m = month
    val mStr = if (m >= 10) "$m" else "0$m"
    val dStr = if (day >= 10) "$day" else "0$day"
    return "$year.$mStr.$dStr"
}

fun Calendar.toMinutesString(): String {
    val format = SimpleDateFormat("yyyy.MM.dd HH:mm", Locale.getDefault())
    return format.format(Date(timeInMillis))
}

fun Calendar.toSecondsString(): String {
    val format = SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault())
    return format.format(Date(timeInMillis))
}

/**
 * 日期所在的周起止日期
 */
fun Calendar.toWeekString(start: Int, hasYear: Boolean = false): String {
    val pair = thisWeekRange(start)
    val ss = if (hasYear) pair.first.toYMDString() else pair.first.toMDString()
    return "$ss~${pair.second.toMDString()}"
}

/**
 * @return
 * 在给定日期后的多少天，
 * 如果在当给定日期之前则为负
 */
fun Calendar.daysAfter(date: Calendar): Int {
    return when {
        year == date.year -> {
            dayOfYear - date.dayOfYear
        }
        this.before(date) -> {
            val temp = this.copy()
            var diff = this.daysOfThisYear - this.dayOfYear
            temp.addYear(1)
            while (temp.year < date.year) {
                diff += temp.daysOfThisYear
                temp.addYear(1)
            }
            diff += date.dayOfYear
            -diff
        }
        else -> {
            val temp = date.copy()
            var diff = date.daysOfThisYear - date.dayOfYear
            temp.addYear(1)
            while (temp.year < this.year) {
                diff += temp.daysOfThisYear
                temp.addYear(1)
            }
            diff += this.dayOfYear
            diff
        }
    }
}

/**
 * @return
 * 在给定日期前的多少天，
 * 如果在当给定日期之后则为负
 */
fun Calendar.daysBefore(date: Calendar): Int {
    return date.daysAfter(this)
}
